﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.ObjectModel;
using TByte.XnaHelper.Input;

namespace TByte.XnaHelper.GameObjects
{
    public class GameObject
    {
        #region Fields
        protected Texture2D texture;
        protected Color color = Color.White;
        protected GameObject parent;
        protected List<GameObject> children = new List<GameObject>();
        protected string name;
        public Vector2 RelativePosition;
        #endregion

        #region Methods
        public virtual void Draw(SpriteBatch spriteBatch)
        {
            foreach (GameObject child in children)
            {
                child.Draw(spriteBatch);
            }
        }
        public virtual void Update()
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.Update();
                }
            }
        }
        public virtual void AddChild(GameObject gameObject)
        {
            gameObject.Parent = this;
            if (!children.Contains(gameObject))
            {
                children.Add(gameObject);
            }
        }
        public virtual void RemoveChild(GameObject gameObject)
        {
            if (children.Contains(gameObject))
            {
                gameObject.parent = null;
                children.Remove(gameObject);
            }
        }
        public GameObject FindRoot()
        {
            if (this.parent == null)
            {
                return this;
            }
            else
            {
                return parent.FindRoot();
            }
        }
        public GameState FindGameState()
        {
            GameObject root = FindRoot();

            foreach (KeyValuePair<string,GameState> pair in Manager.GameStateList)
            {
                if (pair.Value.Root == root)
                {
                    return pair.Value;
                }
            }
            return null;
        }
        public GameObject FindObject(string name)
        {
            Queue<GameObject> queue = new Queue<GameObject>();
            queue.Enqueue(this);

            while (queue.Count > 0)
            {
                GameObject ob = queue.Dequeue();

                if (ob.name == name)
                    return ob;

                foreach (GameObject gameOb in ob.children)
                    queue.Enqueue(gameOb);
            }
            return null;
        }

        #region Input
        public virtual void OnKeyUp(KeyEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnKeyUp(e);
                }
            }
        }
        public virtual void OnKeyDown(KeyEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnKeyDown(e);
                }
            }
        }
        public virtual void OnCharacter(CharacterEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnCharacter(e);
                }
            }
        }
        public virtual void OnMouseMove(MouseEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnMouseMove(e);
                }
            }
        }
        public virtual void OnMouseDown(MouseEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnMouseDown(e);
                }
            }
        }
        public virtual void OnMouseUp(MouseEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnMouseUp(e);
                }
            }
        }
        public virtual void OnMouseHover(MouseEventArgs e)
        {
            Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnMouseHover(e);
                }
            }
        }
        public virtual void OnDoubleClick(MouseEventArgs e)
        {
           Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnDoubleClick(e);
                }
            }
        }
        public virtual void OnMouseWheel(MouseEventArgs e)
        {
           Queue<GameObject> queue = new Queue<GameObject>();

            //Add all children to queue
            foreach (GameObject obj in children)
            {
                queue.Enqueue(obj);
            }

            //Traverse queue
            while (queue.Count() > 0)
            {
                GameObject child = queue.Dequeue();

                if (child != null)
                {
                    child.OnMouseWheel(e);
                }
            }
        }
        #endregion
        #endregion

        #region Constructors
        public GameObject(string name)
        {
            this.name = name;
            this.RelativePosition = Vector2.Zero;
        }
        #endregion

        #region Properties
        public GameObject Parent
        {
            get { return parent; }
            set
            {
                if (parent != null)
                {
                    parent.RemoveChild(this);
                }
                parent = value;
            }
        }
        public ReadOnlyCollection<GameObject> Children { get { return children.AsReadOnly(); } }
        public String Name { get { return name; } set { name = value; } }
        public Vector2 Position
        {
            get
            {
                if (parent != null)
                    return RelativePosition + parent.Position;
                else
                    return RelativePosition;
            }
        }
        #endregion
    }
    public enum ControlMode
    {
        AI,Keyboard,GamePad
    }
}
